/**
  * @file       serialize.c
  * @author     const_zpc (any question please send mail to const_zpc@163.com)
  * @brief      数据序列化/反序列化函数实现 + 结构体序列化/反序列化实现
  * @version    0.1
  * @date       2023-04-01
  * 
  * 
  * ********************************************************************************************************************
  * @details    功能列表说明：
  *             + 数据列化/反序列化压缩函数
  *             + 结构体序列化/反序列化实现
  * 
  * ********************************************************************************************************************
  * @par 源码路径: 
  * @par 修改日志: 
  * <table>
  * <tr><th>Date           <th>Version   <th>Author      <th>Description
  * <tr><td>2023-04-01     <td>1.0       <td>const_zpc       <td>初版
  * </table>
  * ********************************************************************************************************************
  */
#include "serialize/serialize.h"
#include <string.h>
#include <stddef.h>

uint8_t *Cot_VarintEncoded(uint8_t *ptr, uint64_t val)
{
    while (val >= 0x80)
    {
        *ptr++ = (uint8_t)val | 0x80;
        val >>= 7;
    } 
    
    *ptr++ = (uint8_t)val;
    
    return ptr;
}

uint8_t *Cot_VarintDecode(uint8_t *ptr, uint64_t *pVal)
{
    uint8_t offset = 0;
    uint64_t result = 0;
    
    do
    {
        result |= (uint64_t)((*ptr) & ~0x80) << offset;
        offset += 7;
    } while (((*ptr++) & 0x80) != 0);
    
    *pVal = result;
    
    return ptr;
}

uint8_t *Cot_ZigzagEncoded(uint8_t *ptr, int64_t val)
{
    return Cot_VarintEncoded(ptr, (uint64_t)((val<<1)^(val>>63)));
}

uint8_t *Cot_ZigzagDecode(uint8_t *ptr, int64_t *pVal)
{
    uint64_t u64val;
    
    ptr = Cot_VarintDecode(ptr, &u64val);
    *pVal = (int64_t)((u64val >> 1) ^ - (u64val&1));

    return ptr;
}

uint8_t *Cot_FloatEncoded(uint8_t *ptr, float val)
{
    union
    {
        float fval;
        uint32_t val;
    }data;

    data.fval = val;

    for (int i = 0; i < 4; i++)
    {
        *(ptr++) = data.val >> (24 - i * 8);
    }
    
    return ptr;
}

uint8_t *Cot_FloatDecode(uint8_t *ptr, float *pVal)
{
    union
    {
        float fval;
        uint32_t val;
    }data;

    data.val = 0;

    for (int i = 0; i < 4; i++)
    {
        data.val = ((uint32_t)*(ptr++) << (24 - i * 8)) | data.val;
    }

    *pVal = data.fval;
    
    return ptr;
}

uint8_t *Cot_DoubleEncoded(uint8_t *ptr, double val)
{
    union
    {
        double fval;
        uint64_t val;
    }data;

    data.fval = val;

    for (int i = 0; i < 8; i++)
    {
        *(ptr++) = data.val >> (56 - i * 8);
    }
    
    return ptr;
}

uint8_t *Cot_DoubleDecode(uint8_t *ptr, double *pVal)
{
    union
    {
        double fval;
        uint64_t val;
    }data;

    data.val = 0;

    for (int i = 0; i < 8; i++)
    {
        data.val = ((uint64_t)*(ptr++) << (56 - i * 8)) | data.val;
    }

    *pVal = data.fval;
    
    return ptr;
}

uint8_t *Cot_StringEncoded(uint8_t *ptr, const char *pszString)
{
    while (*pszString != '\0')
    {
        *ptr++ = *pszString++;
    }

    *ptr++ = '\0';
    return ptr;
}

uint8_t *Cot_StringDecode(uint8_t *ptr, char *pszString)
{
    while (*ptr != '\0')
    {
        *pszString++ = *ptr++;
    }

    ptr++;
    *pszString++ = '\0';
    return ptr;
}